linux pipewire 蓝牙耳机无声

十二月 22, 2025 更新: 九月 02, 2026 [Linux 与系统] #pipewire #bluetooth

解决方案

修改bluetooth策略

sudo vim /etc/bluetooth/main.conf
[Policy]
AutoEnable=true
JustWorksRepairing=always
AutoConnect=true
#  end config

# 删除后重新配置
bluetoothctl devices
sudo cat /var/lib/bluetooth/88:D8:2E:2B:20:09/41:AA:00:56:F4:FC/info
bluetoothctl remove 41:AA:00:56:F4:FC

sudo systemctl restart bluetooth

常用配置与调试工具汇总

工具用途示例命令
bluetoothctl蓝牙配对/连接底层控制info, connect, trust
pactlPipeWire Pulse 兼容控制list sinks/cards, set-card-profile
pw-cliPipeWire 原生节点检查list-objects, inspect
wireplumber 日志策略/自动路由分析journalctl --user-unit=wireplumber -f
helvum (GUI)PipeWire 节点连接可视化helvum(需安装)
qpwgraph (GUI)类似 helvum,Qt 版qpwgraph
btmon蓝牙 HCI 层抓包sudo btmon
dmesg -w内核蓝牙错误dmesg -w
# 1. 检查蓝牙服务是否运行
systemctl --user status pipewire wireplumber
# 必须都是 active (running)
systemctl --user restart wireplumber pipewire pipewire-pulse
sudo systemctl restart bluetooth

# 2. 确认蓝牙硬件启用
rfkill list bluetooth
# 若 soft/hard blocked,执行:
# rfkill unblock bluetooth

# 3. 检查内核模块
lsmod | grep -E 'btusb|bluetooth|snd_bt_sco'
# 应有 bluetooth、btusb、可能还有 snd_bt_sco(用于 HFP)

# 使用 speaker-test 向默认蓝牙设备发送测试音
# 可能需要先用 `aplay -L` 查找具体设备名
speaker-test -D bluez:<设备名> -t wav -c 2

常用命令

wpctl status     # 最常用。控制WirePlumber会话管理器,查看/切换默认设备,调节音量。
wpctl set-mute [ID] 0      # 取消静音
wpctl set-volume [ID] 0.5   # 设置音量为 50%

pw-cli info all  # PipeWire的命令行接口,用于直接与服务器交互,进行低级操作。
pw-dump > dump.json  # 将所有PipeWire对象(节点、设备等)的状态以JSON格式导出,用于详细分析或提交Bug报告
pw-top               #  类似系统top命令,实时显示音频处理节点的性能数据(如延迟、X运行次数)
pw-play ./test.mp3   # 用于直接播放或录制音频文件,进行快速测试

pactl list cards

apt install helvum
helvum

蓝牙

bluetoothctl
> list               # 查看适配器
> show               # 当前适配器详情
> devices            # 已知设备
> info <MAC>         # 查看耳机详情:是否 Connected: yes, Trusted: yes
> connect <MAC>      # 手动连接(有时 GUI 配对未真正连通音频)

# 实时监听 BlueZ D-Bus 消息(高级)
sudo busctl monitor org.bluez
# 或用 btmon(需 root)
sudo btmon
# 这里发现是配对认证失败: 密钥不匹配:你的耳机里可能保存了与这台电脑或其他设备配对的旧密钥: 或者系统升级后默认策略收紧
sudo cat /var/lib/bluetooth/11:11:2E:2B:20:09/22:22:00:56:F4:FC/info
# 这里保存了旧的协商密钥
# 删除耳机,重新配对后正常
bluetoothctl remove 41:AA:00:56:F4:FC
bluetoothctl
> scan on

pipewire 调试

# 列出所有 sink(输出设备)
pactl list sinks short
# 更详细(关键!看 active port 和 profile)
pactl list sinks

# 列出所有 PipeWire 节点(比 pactl 更底层)
pw-cli list-objects | grep -A5 -B5 -i bluetooth
# 查看蓝牙设备节点属性
pw-cli inspect <node-id>  # 如 42

cp /usr/share/wireplumber/bluez-monitor.d/50-bluez-config.lua ~/.config/wireplumber/bluez-monitor.d/
cat > ~/.config/wireplumber/bluez-monitor.d/50-bluez-config.lua<<EOF
bluez_monitor.properties = {
  ["bluez5.auto-switch"] = true,
  ["bluez5.headset-voice"] = true,   -- ← 若你不需要通话,可设为 false
}
EOF

systemctl --user restart wireplumber

# PipeWire 层
pactl get-sink-volume @DEFAULT_SINK@
pactl get-sink-mute @DEFAULT_SINK@

# ALSA 层(有时 PipeWire 未接管)
alsamixer -D pipewire
# 或
alsamixer        # 按 F6 选蓝牙设备(若有)

sudo apt install helvum qpwgraph pavucontrol
# 用 pactl 指定 sink 播放测试音
pactl play-sample bell-window bluez_output.XX_XX_XX_XX_XX_XX.a2dp-sink
# 或用 pw-play(PipeWire 原生命令)
pw-play --target=bluez_output.XX_XX_XX_XX_XX_XX.a2dp-sink /usr/share/sounds/alsa/Front_Center.wav

排查记录

只有声音没有麦克风?

解决方案

案例(2026-09):显示"已连接"却从扬声器出声 —— gdm 登录界面抢占蓝牙音频注册权

现象

GNOME 蓝牙面板显示耳机已连接,但声音一直从扬声器出。wpctl status / pactl list cards short 里根本没有蓝牙声卡(只有 built-in 声卡)。

关键认知:蓝牙"已连接" ≠ 音频链路已建立。 耳机和电脑之间可能只挂着 LE(低功耗)链路——GATT 电量能正常读(bluetoothctl info 里有 Battery Percentage),GNOME 就显示"已连接",但 A2DP 音频链路从未建立。本案例中连接名带 _LE 后缀(xxx_LE),经典链路连上后名字变成 xxx,可据此识别当前挂的是哪条链路。

排查链

  1. bluetoothctl info <MAC> 显示 Connected: yes,但 bluetoothd 日志全是失败:
    a2dp-sink profile connect failed for XX:XX:XX:XX:XX:XX: Device or resource busy
    avdtp.c:cancel_request() Discover: Connection timed out (110)
    
    跨越数天多次尝试(8/27、8/28、9/2)全部同样失败。本案例其实叠了两个独立问题:
    • 耳机同时连了手机:多设备耳机通常把经典 A2DP 链路让给"优先/最后连接"的设备。手机蓝牙一关,重连立刻成功。这类耳机行为,不是电脑故障。
    • 常驻主因:gdm 抢占注册(见下)。
  2. 手机断开、经典链路通了之后(BlueZ 出现 Endpoint sep1/sep2 和 Transport .../fdN),PipeWire 里依然没有蓝牙声卡;wireplumber 日志:
    RegisterProfile() failed: org.bluez.Error.NotPermitted
    Properties changed in unknown transport '/org/bluez/hci0/dev_XX/dev_AA_BB_CC_DD_EE_FF/sep1/fd3'.
    Multiple sound server instances (PipeWire/Pulseaudio/bluez-alsa) are probably trying to use Bluetooth audio at the same time ...
    

根因:GDM 登录界面抢占了 profile 注册权

gdm 是干什么的?为什么它会有音频服务?

GDM(GNOME Display Manager)是 Ubuntu 的显示管理器,负责开机后的登录界面、多用户切换界面。登录界面(greeter)运行在独立系统用户 gdm 下,它本身也是一整套 GNOME 会话(gnome-shell + 自己的 systemd user 实例),所以也有自己的 pipewire/wireplumber——登录界面也要能播放提示音、辅助功能音效。

这套 gdm 音频服务由 socket 激活触发(比如登录界面某次音频请求),启动后常驻不退出,而且它注册的蓝牙 profile 不会因为用户会话存在而让位。本机实例:8/12 16:32 greeter 音频栈启动并注册成功(ps 可见 gdm 用户的 wireplumber),此后用户会话的 wireplumber 无论怎么重启都注册失败。蓝牙声卡从那天起就没了:日志显示 8/27 起每次连接尝试都失败,而"以前成功过"正是 8/12 16:32 之前。(用户会话 8/12 上午先启动,注册权却被下午的 greeter 拿走——注册只有"成功/失败"两态,谁先注册成功谁持有,另一方被拒;历史细节随日志轮转已不可考。)

"profile 注册权"是什么?

蓝牙音频协议栈分两层:

两层通过 D-Bus 协作。声音服务器启动时向 BlueZ 的 ProfileManager1 接口调用 RegisterProfile(uuid, ...) 登记自己支持的蓝牙音频 profile(A2DP 高音质播放、HFP/HSP 通话等),相当于宣告:"这类音频服务由我提供,设备连上来就找我。"(A2DP/HFP/HSP 对应 UUID 都在其中,见 libspa-bluez5。)

BlueZ 对每个 profile UUID 全系统只允许一个注册者——这是合理设计:一套系统本该只有一个声音服务器。后来者注册同一 UUID 会被拒:

org.bluez.Error.NotPermitted

谁注册成功,谁就持有"注册权"直到其会话退出;之后任何新注册(新用户登录、重启 wireplumber、另一用户的会话)都被拒绝。wireplumber 注册被拒后认为"蓝牙音频已被别的服务器管理",整个 bluez5 模块放弃工作,于是该会话的 PipeWire 里永远不会出现蓝牙声卡,声音只能从扬声器出——与现象完全吻合。

修复(实测有效)

# 1. 停掉 gdm(登录界面)的音频栈,释放注册权(会弹 sudo 确认框)
sudo -u gdm env XDG_RUNTIME_DIR=/run/user/$(id -u gdm) systemctl --user stop wireplumber pipewire pipewire-pulse

# 2. 重启自己的 wireplumber 重新注册,并重连耳机
systemctl --user restart wireplumber
bluetoothctl disconnect <MAC>
bluetoothctl connect <MAC>

# 3. 确认蓝牙 sink 出现并设为默认、解除静音
wpctl status                        # 应出现 [bluez5] 设备与耳机 sink
wpctl set-default <sink-id>
wpctl set-mute <sink-id> 0
wpctl set-volume <sink-id> 0.6

防复发:mask gdm 的音频 unit(登录界面没有音频需求,代价只是登录界面不出声)。gdm 的 home 是 /var/lib/gdm3,把 user unit 软链到 /dev/null 即 mask,重启/锁屏后不会再自动启动:

sudo mkdir -p /var/lib/gdm3/.config/systemd/user
sudo bash -c 'cd /var/lib/gdm3/.config/systemd/user && \
  for u in wireplumber.service pipewire.service pipewire-pulse.service \
           pipewire.socket pipewire-pulse.socket; do ln -sf /dev/null "$u"; done'

自查清单(声音留在扬声器 / 蓝牙无声时)

  1. wpctl status 有没有 [bluez5] 设备?没有 → 音频服务器层面就没拿到蓝牙。
  2. journalctl --user -u wireplumber | grep RegisterProfile:出现 NotPermitted → 注册权被别的会话抢了。
  3. ps -eo user,args | grep wireplumber:出现 gdm 或其他已登录用户的 wireplumber → 就是它抢的(多用户/登录界面都会各起一套音频栈)。
  4. 若注册正常但 bluetoothctl 反复 Discover: Connection timed out / Host is down:多为耳机经典链路被手机等其他设备占用,从耳机侧断开其它设备即可。